gtk: Use GskRenderNode to render widgets
authorEmmanuele Bassi <ebassi@gnome.org>
Thu, 23 Jun 2016 16:35:42 +0000 (17:35 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Tue, 18 Oct 2016 10:49:06 +0000 (11:49 +0100)
We need a virtual function to retrieve the GskRenderNode for each
widget, which is supposed to attach its own children's GskRenderNodes.
Additionally, we want to maintain the existing GtkWidget::draw mechanism
for widgets that do not implement get_render_node() — as well as widgets
that have handlers connected to the ::draw signal.

gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/gtkwidgetprivate.h
gtk/gtkwindow.c

index 2854d07c7cc2b2bc0bf817214978fa6100ff9e69..b16cf8bc6dec4d42152a5fc5aa575ada71f08cd6 100644 (file)
@@ -15827,27 +15827,116 @@ gtk_widget_reset_controllers (GtkWidget *widget)
     }
 }
 
+GskRenderer *
+gtk_widget_get_renderer (GtkWidget *widget)
+{
+  GtkWidget *toplevel;
+
+  toplevel = _gtk_widget_get_toplevel (widget);
+  if (_gtk_widget_is_toplevel (toplevel))
+    return gtk_window_get_renderer (GTK_WINDOW (toplevel));
+
+  return NULL;
+}
+
+GskRenderNode *
+gtk_widget_get_render_node (GtkWidget   *widget,
+                            GskRenderer *renderer)
+{
+  GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
+  GskRenderNode *node;
+
+  if (klass->get_render_node == NULL)
+    {
+      GskRenderNode *tmp;
+      graphene_rect_t bounds;
+      GtkAllocation clip;
+      cairo_t *cr;
+
+      gtk_widget_get_clip (widget, &clip);
+      graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
+
+      tmp = gsk_render_node_new ();
+      gsk_render_node_set_bounds (tmp, &bounds);
+      cr = gsk_render_node_get_draw_context (tmp);
+
+      gtk_widget_draw (widget, cr);
+
+      cairo_destroy (cr);
+
+      node = tmp;
+    }
+  else
+    {
+      node = klass->get_render_node (widget, renderer);
+
+      if (klass->draw != NULL ||
+          g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
+        {
+          GskRenderNode *tmp;
+          graphene_rect_t bounds;
+          GtkAllocation clip;
+          gboolean result;
+          cairo_t *cr;
+
+          gtk_widget_get_clip (widget, &clip);
+          graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
+
+          tmp = gsk_render_node_new ();
+          gsk_render_node_set_bounds (tmp, &bounds);
+          cr = gsk_render_node_get_draw_context (tmp);
+
+          if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
+            {
+              g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
+            }
+          else if (klass->draw != NULL)
+            {
+              klass->draw (widget, cr);
+            }
+
+          cairo_destroy (cr);
+
+          if (node != NULL)
+            {
+              gsk_render_node_append_child (node, tmp);
+              gsk_render_node_unref (tmp);
+            }
+          else
+            {
+              node = tmp;
+            }
+        }
+    }
+
+  return node;
+}
+
 void
 gtk_widget_render (GtkWidget            *widget,
                    GdkWindow            *window,
                    const cairo_region_t *region)
 {
   GdkDrawingContext *context;
-  gboolean do_clip;
-  cairo_t *cr;
-  int x, y;
+  GskRenderer *renderer;
+  GskRenderNode *root;
 
   /* We only render double buffered on native windows */
   if (!gdk_window_has_native (window))
     return;
 
-  context = gdk_window_begin_draw_frame (window, region);
-  cr = gdk_drawing_context_get_cairo_context (context);
+  renderer = gtk_widget_get_renderer (widget);
+  if (renderer == NULL)
+    return;
 
-  do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
-  cairo_translate (cr, -x, -y);
+  root = gtk_widget_get_render_node (widget, renderer);
+  if (root == NULL)
+    return;
+
+  context = gdk_window_begin_draw_frame (window, region);
 
-  gtk_widget_draw_internal (widget, cr, do_clip);
+  gsk_renderer_render (renderer, root, context);
+  gsk_render_node_unref (root);
 
   gdk_window_end_draw_frame (window, context);
 }
index 9d05b7eddb18615e3626290d6dde6847c2683371..41ef61365c1ec2b37dcc14e22916119d5a3c6955 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 #include <gdk/gdk.h>
+#include <gsk/gsk.h>
 #include <gtk/gtkaccelgroup.h>
 #include <gtk/gtkborder.h>
 #include <gtk/gtktypes.h>
@@ -593,12 +594,14 @@ struct _GtkWidgetClass
   void         (*queue_draw_region)           (GtkWidget         *widget,
                                               const cairo_region_t *region);
 
+  GskRenderNode *(* get_render_node) (GtkWidget *widget,
+                                      GskRenderer *renderer);
+
   /*< private >*/
 
   GtkWidgetClassPrivate *priv;
 
   /* Padding for future expansion */
-  void (*_gtk_reserved6) (void);
   void (*_gtk_reserved7) (void);
 };
 
index a9fcb46480bbb653d56b477ac08160cc55c2c7fd..4903d06d23fef9c186042ed3d9bfc23719d24abf 100644 (file)
@@ -296,6 +296,9 @@ void              gtk_widget_render                        (GtkWidget
                                                             const cairo_region_t *region);
 
 
+GskRenderNode *   gtk_widget_get_render_node               (GtkWidget   *widget,
+                                                            GskRenderer *renderer);
+
 /* inline getters */
 
 static inline gboolean
index 122982a41902baa03e4c51a44a3cad86f10af136..415af941c1ee3f280dab8433ed52b915ce67375d 100644 (file)
@@ -7252,6 +7252,8 @@ _gtk_window_set_allocation (GtkWindow           *window,
     {
       graphene_rect_t viewport;
       graphene_matrix_t projection;
+      graphene_matrix_t modelview;
+      graphene_point3d_t tmp;
 
       graphene_rect_init (&viewport, 0, 0, allocation->width, allocation->height);
       gsk_renderer_set_viewport (priv->renderer, &viewport);
@@ -7261,6 +7263,10 @@ _gtk_window_set_allocation (GtkWindow           *window,
                                   0, allocation->height,
                                   -1, 1);
       gsk_renderer_set_projection (priv->renderer, &projection);
+
+      graphene_matrix_init_translate (&modelview,
+                                      graphene_point3d_init (&tmp, 0.f, 0.f, 0.f));
+      gsk_renderer_set_modelview (priv->renderer, &modelview);
     }
 
   get_shadow_width (window, &window_border);